/*
 * @(#)CountDownLatchSolver.java    Jul 27, 2010
 *
 * Copyright 2009 Nyber(Shanghai Itd. All rights reserved.
 */

package com.lab.util.concurrent;

import static java.lang.System.out;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Class description goes here.
 *
 * @author nickevin@gmail.com
 * @version Jul 27, 2010 5:15:14 PM
 */

class TaskPortion implements Runnable {

	private static int counter = 0;
	private final int id = counter++;
	private static Random rand = new Random(47);
	private final CountDownLatch latch;

	TaskPortion(CountDownLatch latch) {
		this.latch = latch;
	}

	public void run() {
		try {
			doWork();
			latch.countDown(); // 减锁存器的计数, 如果计数到达零, 则释放所有等待的线程.
		} catch (InterruptedException ex) {
			// Acceptable way to exit 
		}
	}

	public void doWork() throws InterruptedException {
		TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000));
		out.println(this + "completed");
	}

	@Override
	public String toString() {
		return String.format("%1$-3d ", id);
	}
}

class WaitingTask implements Runnable {

	private static int counter = 0;
	private final int id = counter++;
	private final CountDownLatch latch;

	WaitingTask(CountDownLatch latch) {
		this.latch = latch;
	}

	public void run() {
		try {
			latch.await(); // 使当前线程在倒计数至零之前一直等待.
			out.println("Latch barrier passed for " + this);
		} catch (InterruptedException ex) {
			out.println(this + " interrupted");
		}
	}

	@Override
	public String toString() {
		return String.format("WaitingTask %1$-3d ", id);
	}
}

class Race {

	private Random rand = new Random();
	private int distance = rand.nextInt(250);
	final CountDownLatch start;
	final CountDownLatch finish;

	private List<String> horses = new ArrayList<String>();

	public Race(String... names) {
		horses.addAll(Arrays.asList(names));
		start = new CountDownLatch(1);
		finish = new CountDownLatch(horses.size());
	}

	public void run() throws InterruptedException {
		System.out.println("各赛马起跑门栅前就位...");
		final List<String> places = Collections
				.synchronizedList(new ArrayList<String>());

		for (final String h : horses) {
			new Thread(new Runnable() {
				public void run() {
					try {
						System.out.println(h + " 已就位...");
						start.await();

						int traveled = 0;
						while (traveled < distance) {
							Thread.sleep(rand.nextInt(3) * 1000);

							// ... a horse travels 0-14 lengths
							traveled += rand.nextInt(15);
							System.out.println(h + " 跑到了第 " + traveled + "米!");
						}
						finish.countDown(); // 计数器递减. 当为0时, 则释放线程.
						System.out.println(h + " 穿过终点线!");
						places.add(h);
					} catch (InterruptedException intEx) {
						System.out.println("比赛终止!!!");
						intEx.printStackTrace();
					}
				}
			}).start();
		}

		System.out.println("开闸...");
		start.countDown();

		finish.await(); // 等待计数器为0.
		System.out.println("比赛结果: ");
		System.out.println(places.get(0) + " 冠军...");
		System.out.println(places.get(1) + " 亚军...");
		System.out.println(places.get(2) + " 季军.");
	}

	public int getDistance() {
		return distance;
	}

	public void setDistance(int distance) {
		this.distance = distance;
	}
}
